import * as bfun from '../../core/fbyte.js';
import BNode from './bnode2.js';

/*
 自研压缩算法,小于1024字节无需压缩
	通用压缩法:适用于无法确定内容的压缩场景
	如果经常出现多个相同字节靠在一起 ,需要用其他的压缩算法
*/
function HZip(bc) {
	let root = BNode.newCreate();
	let 步长 = bc || 8; //步长就是缓存
	/**
	 * 添加一个字节流
	 * @param {Uint8Array} bytes
	 */
	function add(bytes) {
		root = BNode.newCreate();
		
		let bn = 0;
		let tag = [];	
		foreach(bytes, (ui) => {
			let 叶 = BNode.setn(root, ui);					
			bn++;
		});
		let n=BNode.sort_id(root);
		let end = foreach(bytes, (ui) => {
			let 叶 = BNode.get(root, ui);	
			//console.log(叶.code)
			tag.push(叶.code); //实现替换
		});	
		//bn:数据块长度不含最后块 , n:字典表长度
		//tag:替换表 end:最后字节串
		return {bn, n, tag, end};		
	}
	//分解字节流,成固定长度的字节,遍历所有
	let foreach = function(bytes, callback) {
		let i = 0;
		while (i + 步长 < bytes.length) {
			let ui = bytes.subarray(i, i + 步长);
			callback(ui);
			i += 步长;
		}
		if (i < bytes.length) {
			let ui = bytes.subarray(i);
			return ui;
		}
		return null;
	}



	this.test = function(bytes) {
		let tb = add(bytes);		
		BNode.view(root);
		console.log("-------------------");	
		let d1 =BNode. list_ui8(BNode.tree_list(root)) ;
		console.log("树列", d1);
		let d2 = BNode.ui8_tree(d1);
		//console.log("树", d2);
		BNode.view(root);

	}
	this.zip = function(bytes) {
		function rep_id(a, 字长) {
			if (字长 == 1) {
				return a;
			} else if (字长 == 2) {
				return bfun.shortToByte2(a);
			} else {
				return bfun.intToByte4(a);
			}
		}
		let tb = add(bytes);
		let 字长 = (tb.n < 256) ? 1 : (tb.n < 65535) ? 2 : 4;
		let d1 = BNode.tree_list(root);
		//console.log("树列", d1);
		let d2 = BNode.list_ui8(d1);
		let tag2 = [];
		for (let i = 0; i < tb.bn; i++) {
			tag2[i] = rep_id(tb.tag[i],字长);
		}
		//console.log("替换",tb.tag)
		let u83 = new Uint8Array(tag2.flat());	//最终数据

		let u82 = new Uint8Array(11 + d2.length);
		u82.set([1], 0); //可压缩
		//步长
		u82.set([步长], 1);
		//字长
		u82.set([字长], 2);
		//数据块	
		u82.set(bfun.intToUi8(tb.bn), 3);
		//表长
		u82.set(bfun.intToUi8(d2.length), 7);
		//console.log(1,步长,字长,tb.bn,d2.length)
		//插入表字典		
		u82.set(d2, 11);
		//console.log(tb);	
		return bfun.concatUi8Arr(u82, u83, tb.end)
	}

	this.unzip = function(bytes) {
		
		
		//如果不压缩直接输出
		if (bytes[0] == 0) return bytes.slice(1);
		步长 = bytes[1];
		let 字长 = bytes[2];
		//console.log(字长)
		let 块 = bfun.byte4ToInt(bytes, 3);
		let 表长 = bfun.byte4ToInt(bytes, 7);
		//console.log(bytes[0],步长,字长,块,表长)
		let n = 11 + 表长;
		//解析表部分
		let root = BNode .ui8_tree(bytes.subarray(11, n), 字长);
		let mp=BNode.sort_kv(root);
		//console.log(mp)
		//数据 +1 =+end块
		let u82 = new Uint8Array((块 + 1) * 步长);
		let i = 0;
		let j = 0;
		
		//解析数据部分
		let toint= (字长 == 1) ?function(b1,off){return b1[off];} : (字长 == 2) ?bfun.byte2ToShort :bfun.byte4ToInt;
			//console.log(块,字长,toint([2],0))
		while (i < 块) {
			//console.log(n, n + 字长,bytes.subarray(n, n + 字长),bytes.subarray(n))
			let key = toint(bytes.subarray(n, n + 字长),0);
			n += 字长;
			i++;
			let rep = mp.get(key);
			//console.log(key,rep)
			u82.set(rep, j);
			j += 步长;
		}
		if (n < bytes.length) {
			let uc = bytes.subarray(n);
			u82.set(uc, j);
			j += uc.length;
		}
		return u82.slice(0, j);
	}
	this.show = function() {
		return root;
	}
}
export default HZip;
